package com.qiaofang.applet.service.other.service.impl;

import com.google.common.collect.Lists;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.context.QfContext;
import com.qiaofang.applet.common.context.QfContextHolder;
import com.qiaofang.applet.common.exception.BusinessException;
import com.qiaofang.applet.constants.MySignStatusEnum;
import com.qiaofang.applet.constants.SignContactStatusEnum;
import com.qiaofang.applet.service.other.domain.SignContact;
import com.qiaofang.applet.service.other.repository.SignContactRepository;
import com.qiaofang.applet.service.other.service.SignContactService;
import com.qiaofang.applet.service.other.service.dto.SignContactListDto;
import com.qiaofang.applet.service.other.service.dto.SignContactQueryDto;
import com.qiaofang.applet.service.other.service.mapstruct.SignContactMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Author: youqing.yang
 * @Create: 2020/10/23 15:20
 * @Description:
 **/
@Slf4j
@Service
public class SignContactServiceImpl extends MongoBaseService<SignContact, String> implements SignContactService {

    private final SignContactRepository  signContactRepository;

    public SignContactServiceImpl(MongoRepository<SignContact, String> repository, SignContactRepository signContactRepository) {
        super(repository);
        this.signContactRepository = signContactRepository;
    }

    @Autowired
    private SignContactMapper signContactMapper;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public Page<SignContact> listSignContact(SignContactQueryDto queryDto, Pageable pageable) {
        // 1、拼查询公共条件
        Query queryCriteria = createFindQuery(queryDto);

        // 2、查询记录总数
        long count = mongoTemplate.count(queryCriteria, SignContact.class);
        List<SignContact> contentList = new ArrayList<>();
        if (count > 0) {
            // 2、拼分页参数
            queryCriteria.with(pageable);
            queryCriteria.with(Sort.by(Sort.Order.desc("startSignTime")));
            contentList = Optional.ofNullable(mongoTemplate.find(queryCriteria, SignContact.class)).orElseGet(Lists::newArrayList)
                    .stream().peek(item -> {
                        item.setSignStatus(SignContactStatusEnum.getValueByCode(item.getSignStatus()));
                        item.setStatus(MySignStatusEnum.getValueByCode(item.getStatus()));
                    }).filter(distinctByKey(SignContact::getContactUuid)).collect(Collectors.toList());
        }
        return PageableExecutionUtils.getPage(contentList, pageable, () -> count);
    }

    @Override
    public Page<SignContactListDto> convertDomainToEstateListDto(Page<SignContact> signContactPage) {
        List<SignContactListDto> content = new ArrayList<>();
        if (signContactPage.getTotalElements() > 0) {
            content = signContactPage.getContent().stream().map(signContactMapper::domainToDto).collect(Collectors.toList());
        }
        return PageableExecutionUtils.getPage(content, signContactPage.getPageable(), () -> signContactPage.getTotalElements());
    }

    @Override
    public SignContact findBySignatoriesUuidAndCompanyUuid(String signatoriesUuid, String companyUuid) {
        return signContactRepository.findBySignatoriesUuidAndCompanyUuid(signatoriesUuid, companyUuid);
    }

    /**
     * 验证是否可以放入set集合中,用来判重
     *
     * @param keyExtractor
     * @param <T>
     * @return
     */
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> set = ConcurrentHashMap.newKeySet();
        return t -> set.add(keyExtractor.apply(t));
    }

    private Query createFindQuery(SignContactQueryDto queryDto) {
        Query query = new Query();

        QfContext qfContext = QfContextHolder.getContext();

        Criteria criteria = Criteria.where("corporationCode").is(qfContext.getCorporationCode());

        criteria.and("phone").is(queryDto.getPhone());

        //合同签约状态
        switch (queryDto.getSignStatus()) {
            case 0:
                criteria.and("signStatus").in(SignContactStatusEnum.SIGN_ING.getCode(), SignContactStatusEnum.SIGN_SUCCESS.getCode(),
                        SignContactStatusEnum.SIGN_FAIL.getCode(), SignContactStatusEnum.CONTACT_CANCEL.getCode());
                break;
            case 1:
                criteria.and("signStatus").is(SignContactStatusEnum.SIGN_ING.getCode());
                break;
            case 2:
                criteria.and("signStatus").is(SignContactStatusEnum.SIGN_SUCCESS.getCode());
                break;
            case 3:
                criteria.and("signStatus").in(SignContactStatusEnum.SIGN_FAIL.getCode(), SignContactStatusEnum.CONTACT_CANCEL.getCode());
                break;
            default:
                throw new BusinessException("合同签约状态传参错误：请输入正确范围 0~3");
        }
        //我的签约状态
        switch (queryDto.getStatus()) {
            //全部
            case 0:
                criteria.and("status").in(MySignStatusEnum.SIGNING.getCode(), MySignStatusEnum.WAITING.getCode(),
                        MySignStatusEnum.SIGNED.getCode(), MySignStatusEnum.INVALIDED.getCode()
                        , MySignStatusEnum.EXPIRED.getCode(), MySignStatusEnum.REJECTED.getCode());
                break;
            //待签约
            case 1:
                criteria.and("status").in(MySignStatusEnum.SIGNING.getCode(), MySignStatusEnum.WAITING.getCode());
                break;
            //我已签约
            case 2:
                criteria.and("status").in(MySignStatusEnum.SIGNED.getCode(), MySignStatusEnum.INVALIDED.getCode(),
                        MySignStatusEnum.EXPIRED.getCode());
                break;
            //拒绝签约
            case 3:
                criteria.and("status").is(MySignStatusEnum.REJECTED.getCode());
                break;
            default:
                throw new BusinessException("我的签约状态传参错误：请输入正确范围 0~3");
        }
        query.addCriteria(criteria);
        return query;
    }
}
